﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using TowerDefence.Entities.States;

namespace TowerDefence.Tiles
{
    /// <summary>
    /// Creates tiles, who knew?
    /// </summary>
    public class TileFactory
    {
        private const string AI_RED = "ai_red";
        private const string AI_GREEN = "ai_green";
        private const string AI_BLUE = "ai_blue";
        private const string AI_PURPLE = "ai_purple";

        public IEnumerable<ITile> CreateTiles(Map _map)
        {
            List<ITile> tiles = new List<ITile>();

            // get the tileset that is used in the logical layer
            var tileSet = (from t in _map.Tilesets where t.Name == "logicalTiles" select t).First();

            // get the logical layer (the superimposed path/mountpoints/etc)
            var logicalLayer = (from l in _map.Layers where l.Name == "logical" select l).First();

            // get the ai_path layers
            var aipathLayers = from l in _map.Layers where l.Name.StartsWith("ai_") select l;
            var aipathTiles = from t in _map.Tilesets where t.Name.StartsWith("ai_") select t;            
                       
            // create objects
            for (int x = 0; x < _map.Width; x++)
            {
                for (int y = 0; y < _map.Height; y++)
                {
                    string tileType = GetTileProperty(logicalLayer, tileSet, x, y, "type");
                    if (tileType == null) continue;

                    // Get any ai path directions on this tile
                    var directions = new Dictionary<eAIPath, eAIDir>();
                    foreach (var layer in aipathLayers)
                    {
                        var aiTileset = (from t in aipathTiles where t.Name == layer.Name select t).First();
                        string direction = GetTileProperty(layer, aiTileset, x, y, "direction");
                        if (direction == null) continue;
                        eAIDir eDir = (eAIDir)(-1);
                        switch (direction.ToLower())
                        {
                            case "up":
                                eDir = eAIDir.UP;
                                break;
                            case "down":
                                eDir = eAIDir.DOWN;
                                break;
                            case "left":
                                eDir = eAIDir.LEFT;
                                break;
                            case "right":
                                eDir = eAIDir.RIGHT;
                                break;
                        }
                        switch (layer.Name)
                        {
                            case AI_RED:
                                directions.Add(eAIPath.RED, eDir);
                                break;
                            case AI_GREEN:
                                directions.Add(eAIPath.GREEN, eDir);
                                break;
                            case AI_BLUE:
                                directions.Add(eAIPath.BLUE, eDir);
                                break;
                            case AI_PURPLE:
                                directions.Add(eAIPath.PURPLE, eDir);
                                break;
                        }
                    }

                    var tilepos = new Vector2(x * _map.TileWidth, y * _map.TileHeight);
                    ITile tile = CreateTile(tileType, tilepos, directions);
                    tiles.Add(tile);
                }
            }
            return tiles;
        }

        private string GetTileProperty(Layer _layer, Tileset _tileset, int _x, int _y, string _property)
        {
            int tileIndex = _layer.GetTile(_x, _y);
            TilePropertyList propertyList;
            if (!_tileset.TryGetTileProperties(tileIndex, out propertyList))
            {
                return null;
            }
            return propertyList[_property];
        }

        private Tile CreateTile(string _tileType, Vector2 _position, Dictionary<eAIPath, eAIDir> _directions)
        {
            switch (_tileType)
            {
                case "path":
                    return new PathTile(_position, _directions);
                case "mountPoint":
                    return new MountPoint(_position);
                case "startPoint":
                    return new StartTile(_position, _directions);
                case "goal":
                    return new GoalTile(_position, _directions, 10); // arbitrary 10 point limit
                default:
                    throw new ArgumentException(String.Format("Can't create a {0} tile", _tileType), "_tileType");
            }
        }
    }
}
